<template>
  <div class="cube-basic">
    <h1>立方体</h1>
    <p>
      在WebGL中，立方体是一个基本的3D图形。通过立方体的绘制，我们可以学习WebGL中的3D渲染、矩阵变换和深度测试等重要概念。
    </p>

    <el-card class="demo-section">
      <template #header>
        <div class="card-header">
          <h3>立方体的绘制</h3>
        </div>
      </template>
      <div class="demo-content">
        <canvas ref="canvas" width="400" height="400"></canvas>
        <div class="control-panel">
          <p>这是一个自动旋转的立方体，每个面都有不同的颜色：</p>
          <ul>
            <li>前面：红色</li>
            <li>后面：绿色</li>
            <li>顶面：蓝色</li>
            <li>底面：黄色</li>
            <li>右面：紫色</li>
            <li>左面：青色</li>
          </ul>
        </div>
      </div>
    </el-card>

    <el-card class="code-section">
      <template #header>
        <div class="card-header">
          <h3>示例代码</h3>
        </div>
      </template>
      <div class="code-content">
        <pre><code>
// 顶点着色器
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;

void main() {
  gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
  v_Color = a_Color;
}

// 片元着色器
precision mediump float;
varying vec4 v_Color;

void main() {
  gl_FragColor = v_Color;
}

// JavaScript代码
const canvas = document.getElementById('webgl');
const gl = canvas.getContext('webgl');

// 创建着色器程序...

// 设置顶点位置和颜色
const vertices = new Float32Array([
  // 前面（红色）
  -0.5, -0.5,  0.5,  1.0, 0.0, 0.0,
   0.5, -0.5,  0.5,  1.0, 0.0, 0.0,
   0.5,  0.5,  0.5,  1.0, 0.0, 0.0,
  -0.5,  0.5,  0.5,  1.0, 0.0, 0.0,
  // 更多顶点数据...
]);

// 设置顶点索引
const indices = new Uint8Array([
  0, 1, 2,  0, 2, 3,  // 前面
  // 更多索引数据...
]);

// 设置矩阵变换
const modelMatrix = new Float32Array(16);
const viewMatrix = new Float32Array(16);
const projMatrix = new Float32Array(16);

// 绘制立方体
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);
        </code></pre>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { WebGLUtils } from '../../utils/webgl'

const canvas = ref<HTMLCanvasElement | null>(null)

// 顶点着色器
const vertexShaderSource = `
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;

void main() {
  gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
  v_Color = a_Color;
}
`

// 片元着色器
const fragmentShaderSource = `
precision mediump float;
varying vec4 v_Color;

void main() {
  gl_FragColor = v_Color;
}
`

// 立方体的顶点坐标
const vertices = new Float32Array([
  // 前面
  -0.5, -0.5,  0.5,  1.0, 0.0, 0.0,  // 红色
   0.5, -0.5,  0.5,  1.0, 0.0, 0.0,
   0.5,  0.5,  0.5,  1.0, 0.0, 0.0,
  -0.5,  0.5,  0.5,  1.0, 0.0, 0.0,
  // 后面
  -0.5, -0.5, -0.5,  0.0, 1.0, 0.0,  // 绿色
  -0.5,  0.5, -0.5,  0.0, 1.0, 0.0,
   0.5,  0.5, -0.5,  0.0, 1.0, 0.0,
   0.5, -0.5, -0.5,  0.0, 1.0, 0.0,
  // 顶面
  -0.5,  0.5, -0.5,  0.0, 0.0, 1.0,  // 蓝色
  -0.5,  0.5,  0.5,  0.0, 0.0, 1.0,
   0.5,  0.5,  0.5,  0.0, 0.0, 1.0,
   0.5,  0.5, -0.5,  0.0, 0.0, 1.0,
  // 底面
  -0.5, -0.5, -0.5,  1.0, 1.0, 0.0,  // 黄色
   0.5, -0.5, -0.5,  1.0, 1.0, 0.0,
   0.5, -0.5,  0.5,  1.0, 1.0, 0.0,
  -0.5, -0.5,  0.5,  1.0, 1.0, 0.0,
  // 右面
   0.5, -0.5, -0.5,  1.0, 0.0, 1.0,  // 紫色
   0.5,  0.5, -0.5,  1.0, 0.0, 1.0,
   0.5,  0.5,  0.5,  1.0, 0.0, 1.0,
   0.5, -0.5,  0.5,  1.0, 0.0, 1.0,
  // 左面
  -0.5, -0.5, -0.5,  0.0, 1.0, 1.0,  // 青色
  -0.5, -0.5,  0.5,  0.0, 1.0, 1.0,
  -0.5,  0.5,  0.5,  0.0, 1.0, 1.0,
  -0.5,  0.5, -0.5,  0.0, 1.0, 1.0
])

// 顶点索引
const indices = new Uint8Array([
  0,  1,  2,   0,  2,  3,  // 前面
  4,  5,  6,   4,  6,  7,  // 后面
  8,  9,  10,  8,  10, 11, // 顶面
  12, 13, 14,  12, 14, 15, // 底面
  16, 17, 18,  16, 18, 19, // 右面
  20, 21, 22,  20, 22, 23  // 左面
])

onMounted(() => {
  if (!canvas.value) return

  const gl = canvas.value.getContext('webgl')
  if (!gl) return

  // 创建WebGL工具实例
  const webglUtils = new WebGLUtils(gl)

  // 创建着色器
  const vertexShader = webglUtils.createShader(gl.VERTEX_SHADER, vertexShaderSource)
  const fragmentShader = webglUtils.createShader(gl.FRAGMENT_SHADER, fragmentShaderSource)
  if (!vertexShader || !fragmentShader) return

  // 创建程序并链接着色器
  const program = webglUtils.createProgram(vertexShader, fragmentShader)
  if (!program) return

  gl.useProgram(program)

  // 获取变量位置
  const a_Position = gl.getAttribLocation(program, 'a_Position')
  const a_Color = gl.getAttribLocation(program, 'a_Color')
  const u_ModelMatrix = gl.getUniformLocation(program, 'u_ModelMatrix')
  const u_ViewMatrix = gl.getUniformLocation(program, 'u_ViewMatrix')
  const u_ProjMatrix = gl.getUniformLocation(program, 'u_ProjMatrix')

  // 创建缓冲区
  const vertexBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

  const indexBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)

  // 设置顶点属性
  gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 24, 0)
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 24, 12)
  gl.enableVertexAttribArray(a_Position)
  gl.enableVertexAttribArray(a_Color)

  // 设置视图矩阵
  const viewMatrix = new Float32Array([
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, -5.0, 1.0
  ])

  // 设置投影矩阵（使用透视投影）
  const fov = 45 * Math.PI / 180  // 视角
  const aspect = canvas.value.width / canvas.value.height  // 宽高比
  const near = 0.1  // 近平面
  const far = 100.0  // 远平面

  const f = 1.0 / Math.tan(fov / 2)
  const projMatrix = new Float32Array([
    f / aspect, 0.0, 0.0, 0.0,
    0.0, f, 0.0, 0.0,
    0.0, 0.0, (far + near) / (near - far), -1.0,
    0.0, 0.0, (2 * far * near) / (near - far), 0.0
  ])

  // 设置初始模型矩阵
  let angle = 0
  const modelMatrix = new Float32Array(16)

  // 动画函数
  function animate() {
    if (!gl) return

    angle = (angle + 1) % 360
    const radian = angle * Math.PI / 180

    // 设置旋转矩阵
    modelMatrix[0] = Math.cos(radian)
    modelMatrix[1] = 0
    modelMatrix[2] = -Math.sin(radian)
    modelMatrix[3] = 0
    modelMatrix[4] = 0
    modelMatrix[5] = 1
    modelMatrix[6] = 0
    modelMatrix[7] = 0
    modelMatrix[8] = Math.sin(radian)
    modelMatrix[9] = 0
    modelMatrix[10] = Math.cos(radian)
    modelMatrix[11] = 0
    modelMatrix[12] = 0
    modelMatrix[13] = 0
    modelMatrix[14] = 0
    modelMatrix[15] = 1

    // 清除画布
    gl.clearColor(0.0, 0.0, 0.0, 1.0)
    gl.enable(gl.DEPTH_TEST)
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

    // 更新并绘制
    gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix)
    gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix)
    gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix)
    gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0)

    requestAnimationFrame(animate)
  }

  // 启动动画
  animate()
})
</script>

<style lang="scss" scoped>
.cube-basic {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;

  h1 {
    color: #303133;
    margin-bottom: 20px;
  }

  .demo-section,
  .code-section {
    margin: 30px 0;

    .card-header {
      display: flex;
      align-items: center;

      h3 {
        margin: 0;
        color: #409eff;
      }
    }
  }

  .demo-section {
    .demo-content {
      display: flex;
      gap: 20px;

      canvas {
        border: 1px solid #dcdfe6;
        background-color: #000;
      }

      .control-panel {
        flex: 1;
        padding: 20px;
        background-color: #f8f9fa;
        border-radius: 4px;

        ul {
          list-style-type: none;
          padding-left: 0;

          li {
            margin: 8px 0;
          }
        }
      }
    }
  }

  .code-section {
    .code-content {
      background-color: #f8f9fa;
      padding: 15px;
      border-radius: 4px;

      code {
        font-family: monospace;
        color: #409eff;
      }

      pre {
        margin: 0;
        white-space: pre-wrap;
      }
    }
  }
}
</style>
